(*
 *    _  _   ____                         _  
 *  _| || |_/ ___|  ___ _ __  _ __   ___ | | 
 * |_  ..  _\___ \ / _ \ '_ \| '_ \ / _ \| | 
 * |_      _|___) |  __/ |_) | |_) | (_) |_| 
 *   |_||_| |____/ \___| .__/| .__/ \___/(_) 
 *                     |_|   |_|             
 *
 * Personal Social Web.
 *
 * Copyright (C) The #Seppo contributors. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *)

open Seppo_lib

let test_scanf () =
  Logr.info (fun m -> m "test_scanf");
  (let tup2 a b = (a, b) in
   (let c, t = Scanf.sscanf "4 2022-04-06T14:55:17Z" "%i %s" tup2 in
    Assrt.equals_string __LOC__ "2022-04-06T14:55:17Z" t;
    Assrt.equals_int __LOC__ 4 c);
   try
     let _ = Scanf.sscanf "fail 2022-04-06T14:55:17Z" "%i %s" tup2 in
     assert false
   with Scanf.Scan_failure _msg ->
     Assrt.equals_string __LOC__
       "scanf: bad input at char number 0: character 'f' is not a decimal digit"
       _msg);
  assert true

let test_hash () =
  Logr.info (fun m -> m "test_hash");
  let lut = Hashtbl.create 20 in
  Hashtbl.add lut "127.0.0.1" (1, Ptime.epoch);
  try
    match Hashtbl.find lut "127.0.0.1" with
    | bad, tim ->
      assert (bad = 1);
      assert (tim = Ptime.epoch)
  with Not_found -> assert false

let t_of_sexp sx =
  match sx with
  | Ok
      (Sexplib0.Sexp.List
         [
           Sexplib0.Sexp.Atom adr_;
           Sexplib0.Sexp.Atom sev_;
           Sexplib0.Sexp.Atom tim_;
         ]) ->
    Ok
      ( adr_,
        int_of_string sev_,
        Option.value ~default:Ptime.epoch
          (Ptime.of_float_s (float_of_string tim_)) )
  | _ -> Error "Cannot parse Csexp"

let sexp_of_t (adr, sev, tim) =
  Sexplib0.Sexp.List
    [
      Sexplib0.Sexp.Atom adr;
      Sexplib0.Sexp.Atom (string_of_int sev);
      Sexplib0.Sexp.Atom (string_of_float (Ptime.to_float_s tim));
    ]

module Csexp = Csexp.Make (Sexplib0.Sexp)

let test_csexp () =
  Logr.info (fun m -> m "test_csexp");
  let ban =
    ( "127.0.0.1",
      4,
      Option.value ~default:Ptime.epoch (Ptime.of_float_s 1605912887.3501091) )
  in

  let s = sexp_of_t ban |> Csexp.to_string in
  Assrt.equals_string __LOC__ "(9:127.0.0.11:413:1605912887.35)" s;

  match s |> Csexp.parse_string |> t_of_sexp with
  | Ok (adr', sev', tim') ->
    let adr, sev, tim = ban in
    Assrt.equals_string __LOC__ adr adr';
    Assrt.equals_int __LOC__ sev sev';
    Assrt.equals_float __LOC__ (Ptime.to_float_s tim) (Ptime.to_float_s tim')
      1e-3
  | _ -> assert false


let _test_seq () =
  Logr.info (fun m -> m "test_seq");
  Printf.sprintf "%.0f" 1.0
  |> Assrt.equals_string __LOC__ "1";
  let fn = "tmp/seq.cdb" in
  (try
     Unix.mkdir "tmp" File.pDir;
   with Unix.Unix_error (Unix.EEXIST, _, _) -> ());
  (try
     Unix.unlink fn;
     Unix.unlink (fn ^ "~")
   with Unix.Unix_error (Unix.ENOENT, _, _) -> ());
  File.touch fn;
  let cdb = Mcdb.Cdb fn
  and k = "127.0.0.1"
  and t0 = Ptime.epoch in
  let f x = x *. Ban.chunk_s |> Ptime.Span.of_float_s |> Option.get |> Ptime.add_span t0 |> Option.get in
  let t1 = f 0.5 in
  let _t2 = f 1.5 in
  let _t3 = f 2.5 in
  let t4 = f 3.5 in
  let t5 = f 4.5 in
  Logr.info (fun m -> m "test_seq 1");
  Assrt.equals_none __LOC__ (Ban.check cdb t0 k);
  Logr.info (fun m -> m "test_seq 10");
  Ban.escalate cdb t1 k;
  Mcdb.find_string_opt k cdb
  |> Option.value ~default:"fail"
  |> Assrt.equals_string __LOC__ "1970-01-01T00:15:00-00:00";
  Assrt.equals_none __LOC__ (Ban.check cdb t1 k);
  Ban.escalate cdb t1 k;
  Ban.escalate cdb t1 k;
  Ban.escalate cdb t1 k;
  Ban.check cdb t1 k |> Option.get |> Ptime.to_rfc3339
  |> Assrt.equals_string __LOC__ "1970-01-01T00:25:00-00:00";
  Ban.escalate cdb t4 k;
  Assrt.equals_none __LOC__ (Ban.check cdb t5 k);
  assert true

let () =
  Unix.chdir "../../../test/";
  test_scanf ();
  test_hash ();
  test_csexp ();
  (* test_seq (); *)
  assert true
